// AI 服务：受控生成文字生存事件（测试版）

const DEFAULT_BASE_URL = 'https://api.52vmy.cn/api/chat/spark'; // 52vmy API
const DEFAULT_MODEL = 'spark'; // 52vmy 模型
const DEFAULT_API_KEY = ''; // 52vmy API 无需密钥

class TextSurvivalAIService {
	constructor() {
		this.baseURL = DEFAULT_BASE_URL;
		this.model = DEFAULT_MODEL;
		this.apiKey = DEFAULT_API_KEY;
		this.timeoutMs = 10000; // 52vmy API响应快速，10秒超时足够
	}

	setConfig({ baseURL, model, apiKey, timeoutMs }) {
		if (baseURL) this.baseURL = baseURL;
		if (model) this.model = model;
		if (apiKey) this.apiKey = apiKey;
		if (timeoutMs) this.timeoutMs = timeoutMs;
	}

	async isAvailable() {
		try {
			console.log('AI服务 - 检查可用性，URL:', this.baseURL);
			const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
			const timer = controller ? setTimeout(() => {
				console.log('AI服务 - 可用性检查超时');
				controller.abort();
			}, 10000) : null; // 增加到10秒
			const res = await fetch(`${this.baseURL}?msg=test`, {
				method: 'GET',
				headers: {
					'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
				},
				signal: controller?.signal
			});
			if (timer) clearTimeout(timer);
			console.log('AI服务 - 可用性检查结果:', res.ok, res.status);
			return res.ok;
		} catch (e) {
			console.error('AI服务 - 可用性检查失败:', e);
			return false;
		}
	}

	// 生成受控事件：仅返回JSON对象，字段与现有ChoiceModal一致
	async generateEvent(gameState = {}) {
		const prompt = this.#buildPrompt(gameState);
		console.log('AI服务 - 构建的提示词长度:', prompt.length);
		console.log('AI服务 - 请求URL:', this.baseURL);
		
		try {
			// 提示词简化后，减少超时时间到15秒
			const timeoutMs = 15000;
			const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
			const timer = controller ? setTimeout(() => {
				console.log('AI服务 - 请求超时，正在中断...');
				controller.abort();
			}, timeoutMs) : null;
			
			console.log('AI服务 - 发送请求...');
			const res = await fetch(`${this.baseURL}?msg=${encodeURIComponent(prompt)}`, {
				method: 'GET',
				headers: {
					'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
				},
				signal: controller?.signal
			});
			if (timer) clearTimeout(timer);
			
			console.log('AI服务 - 响应状态:', res.status);
			console.log('AI服务 - 响应头:', res.headers);
			
			if (!res.ok) {
				const errorText = await res.text();
				console.error('AI服务 - 请求失败:', res.status, errorText);
				throw new Error(`AI请求失败: ${res.status} - ${errorText}`);
			}
			
			const data = await res.json();
			console.log('AI服务 - 原始响应:', data);
			
			const text = data?.data?.answer?.trim() || '';
			console.log('AI服务 - 提取的文本:', text);
			
			// 解析AI返回的格式
			const lines = text.split('\n').filter(line => line.trim());
			console.log('AI服务 - 分割后的行:', lines);
			
			if (lines.length === 0) {
				throw new Error('AI返回内容为空');
			}
			
			// 尝试解析新格式（数字开头的选项）
			if (lines.some(line => line.match(/^\d+\./))) {
				console.log('AI服务 - 检测到数字格式，使用新解析方法');
				return this.#parseNumberedFormat(lines);
			}
			
			// 尝试解析管道符格式（行动|风险|效果）
			if (lines.some(line => line.includes('|'))) {
				console.log('AI服务 - 检测到管道符格式，使用管道符解析方法');
				return this.#parsePipeFormat(lines);
			}
			
			// 尝试解析管道符格式
			let dataLine = lines.find(line => line.includes('|'));
			if (!dataLine) {
				// 如果没有找到|分隔符，尝试从第一行开始解析
				console.log('AI服务 - 未找到分隔符，尝试使用第一行');
				dataLine = lines[0];
			}
			
			console.log('AI服务 - 数据行:', dataLine);
			
			// 解析数据行
			const parts = dataLine.split('|').map(p => p.trim());
			console.log('AI服务 - 分割后的部分:', parts);
			
			if (parts.length < 2) {
				throw new Error('AI返回数据不完整');
			}
			
			// 构建事件对象
			const event = {
				id: `ai_event_${Date.now()}`,
				scene: parts[0],
				image: '',
				options: []
			};
			
			// 解析选项
			for (let i = 1; i < parts.length; i++) {
				const optionText = parts[i];
				if (!optionText) continue;
				
				// 如果选项文本包含|，则解析为 行动描述|风险等级|效果描述
				// 否则直接作为行动描述
				const optionParts = optionText.split('|');
				
				const option = {
					label: optionParts[0] || optionText,
					risk: optionParts[1] || '中',
					hints: optionParts[2] || '',
					effects: this.#parseEffects(optionParts[2] || ''),
					requires: {},
					next: null
				};
				
				// 如果没有解析到效果，尝试从标签中解析
				if (!option.effects || Object.keys(option.effects).length === 0) {
					option.effects = this.#parseEffects(optionParts[0] || optionText);
				}
				
				event.options.push(option);
			}
			
			console.log('AI服务 - 构建的事件:', event);
			return event;
		} catch (e) {
			console.error('AI服务 - 生成事件失败:', e);
			console.error('AI服务 - 错误堆栈:', e.stack);
			
			// 特殊处理AbortError
			if (e.name === 'AbortError') {
				throw new Error('AI请求超时，请检查网络连接或稍后重试');
			}
			
			// 处理网络错误
			if (e.message && e.message.includes('fetch')) {
				throw new Error('网络连接失败，请检查网络设置');
			}
			
			throw new Error('AI生成事件失败：' + (e?.message || '未知错误'));
		}
	}

	#buildPrompt(state) {
		const { hp=100, hunger=50, energy=50, day=1, inventory={}, buffs={}, sceneText='', contextPrompt='' } = state || {};
		
		// 根据当前状态生成智能提示
		let smartPrompt = contextPrompt || '';
		if (energy <= 10) {
			smartPrompt += '玩家精力极低，必须提供休息恢复选项，如"休息恢复"、"寻找安全地点休息"等。';
		}
		if (hp <= 30) {
			smartPrompt += '玩家生命危险，必须提供治疗选项，如"寻找草药"、"制作绷带"等。';
		}
		if (hunger >= 80) {
			smartPrompt += '玩家非常饥饿，必须提供食物选项，如"寻找食物"、"制作食物"等。';
		}
		if (energy <= 0) {
			smartPrompt += '玩家精力为0，极度危险！必须提供紧急恢复选项，如"紧急休息"、"寻找能量源"等。';
		}
		
		// 使用管道符分隔格式，更稳定
		return `【场景】{场景描述，40字内，具体环境细节}

【状态】生命${hp}% 饥饿${hunger}% 精力${energy}% | 第${day}天
【背包】[${Object.entries(inventory).filter(([k,v]) => v > 0).map(([k,v]) => `${k}:${v}`).join(',') || '无物品'}]  // 格式：物品1:数量,物品2:数量,...

【行动选项】
每个选项格式：行动|风险|效果(状态变化+资源变化)

${smartPrompt ? `特殊要求：${smartPrompt}` : ''}

{根据场景生成3-4个选项，可创建新物品(如"浆果:2")添加到背包数组中，用逗号分隔}`;
	}


	// 解析管道符格式的选项
	#parsePipeFormat(lines) {
		console.log('AI服务 - 解析管道符格式:', lines);
		
		const event = {
			id: `ai_event_${Date.now()}`,
			scene: '你面前出现了新的挑战。',
			image: '',
			options: []
		};
		
		for (const line of lines) {
			const trimmed = line.trim();
			
			// 检测管道符格式的选项
			if (trimmed.includes('|')) {
				const parts = trimmed.split('|').map(p => p.trim());
				if (parts.length >= 3) {
					const option = {
						label: parts[0],
						risk: parts[1],
						hints: parts[2] || '',
						effects: this.#parseEffects(parts[2] || ''),
						requires: {},
						next: null
					};
					
					event.options.push(option);
				}
			}
		}
		
		console.log('AI服务 - 解析完成的事件:', event);
		return event;
	}

	// 解析数字格式的选项
	#parseNumberedFormat(lines) {
		console.log('AI服务 - 解析数字格式:', lines);
		
		const event = {
			id: `ai_event_${Date.now()}`,
			scene: '你面前出现了新的挑战。',
			image: '',
			options: []
		};
		
		let currentOption = null;
		
		for (const line of lines) {
			const trimmed = line.trim();
			
			// 检测选项开始（数字开头）
			if (trimmed.match(/^\d+\./)) {
				// 保存上一个选项
				if (currentOption) {
					event.options.push(currentOption);
				}
				
				// 开始新选项
				const optionText = trimmed.replace(/^\d+\.\s*/, '');
				currentOption = {
					label: optionText,
					risk: '中',
					hints: '',
					effects: {},
					requires: {},
					next: null
				};
			}
			// 检测风险等级
			else if (trimmed.includes('风险等级') || trimmed.includes('风险')) {
				const riskMatch = trimmed.match(/风险等级?[：:]\s*([低中高])/);
				if (riskMatch && currentOption) {
					currentOption.risk = riskMatch[1];
				}
			}
			// 检测效果
			else if (trimmed.includes('具体效果') || trimmed.includes('效果')) {
				const effectMatch = trimmed.match(/具体效果[：:]\s*(.+)/);
				if (effectMatch && currentOption) {
					currentOption.effects = this.#parseEffects(effectMatch[1]);
				}
			}
			// 检测描述
			else if (trimmed.includes('描述') && !trimmed.includes('具体效果')) {
				const descMatch = trimmed.match(/描述[：:]\s*(.+)/);
				if (descMatch && currentOption) {
					currentOption.hints = descMatch[1];
				}
			}
		}
		
		// 保存最后一个选项
		if (currentOption) {
			event.options.push(currentOption);
		}
		
		console.log('AI服务 - 解析完成的事件:', event);
		return event;
	}

	// 解析效果描述
	#parseEffects(effectText) {
		const effects = {};
		if (!effectText) return effects;
		
		// 解析效果：如"生命+10,精力-5"或"木材+2"
		const matches = effectText.match(/(生命|饥饿|精力|木材|石头|藤蔓|淡水)([+-]?\d+)/g);
		if (matches) {
			matches.forEach(match => {
				const [, type, value] = match.match(/(生命|饥饿|精力|木材|石头|藤蔓|淡水)([+-]?\d+)/);
				const numValue = parseInt(value);
				
				switch (type) {
					case '生命':
						effects.hp = numValue;
						break;
					case '饥饿':
						effects.hunger = numValue;
						break;
					case '精力':
						effects.energy = numValue;
						break;
					case '木材':
					case '石头':
					case '藤蔓':
					case '淡水':
						if (!effects.resources) effects.resources = {};
						effects.resources[type === '木材' ? 'wood' : 
										type === '石头' ? 'stone' : 
										type === '藤蔓' ? 'vine' : 'water'] = numValue;
						break;
				}
			});
		}
		
		// 如果没有解析到效果，尝试从行动描述中推断
		if (Object.keys(effects).length === 0) {
			const text = effectText.toLowerCase();
			if (text.includes('收集') || text.includes('寻找') || text.includes('水源')) {
				effects.resources = { water: 1 };
				effects.energy = -3;
			} else if (text.includes('木材') || text.includes('砍伐')) {
				effects.resources = { wood: 1 };
				effects.energy = -5;
			} else if (text.includes('休息') || text.includes('恢复') || text.includes('睡眠') || text.includes('躺下') || text.includes('放松')) {
				effects.energy = 20;
				effects.hp = 5;
			} else if (text.includes('食物') || text.includes('浆果') || text.includes('吃')) {
				effects.hunger = 10;
				effects.energy = -5;
			} else if (text.includes('紧急') || text.includes('急救') || text.includes('能量')) {
				effects.energy = 25;
				effects.hp = 10;
			} else if (text.includes('制作') || text.includes('建造') || text.includes('工具')) {
				effects.energy = -8;
			} else if (text.includes('探索') || text.includes('搜索') || text.includes('寻找')) {
				effects.energy = -10;
			}
		}
		
		// 解析新物品格式（如"浆果:2"）
		const newItemMatches = effectText.match(/([^,，]+):(\d+)/g);
		if (newItemMatches) {
			if (!effects.resources) effects.resources = {};
			newItemMatches.forEach(match => {
				const [, itemName, amount] = match.match(/([^:：]+):(\d+)/);
				effects.resources[itemName.trim()] = parseInt(amount);
			});
		}
		
		return effects;
	}

	#sanitizeEvent(evt) {
		const safe = {
			id: String(evt?.id || ('ai_' + Date.now())),
			scene: String(evt?.scene || '你面前出现了新的未知挑战。').slice(0, 120),
			image: '',
			options: []
		};
		const opts = Array.isArray(evt?.options) ? evt.options : [];
		for (const o of opts.slice(0,3)) {
			const opt = {
				label: String(o?.label || '继续'),
				risk: ['低','中','高'].includes(o?.risk) ? o.risk : '中',
				hints: o?.hints ? String(o.hints).slice(0, 20) : undefined,
				effects: {},
				requires: undefined,
				next: null
			};
			if (o?.effects && typeof o.effects === 'object') {
				const e = o.effects;
				const resources = e.resources && typeof e.resources === 'object' ? e.resources : undefined;
				opt.effects = {
					hp: typeof e.hp === 'number' ? Math.max(-15, Math.min(15, e.hp)) : undefined,
					hunger: typeof e.hunger === 'number' ? Math.max(-20, Math.min(20, e.hunger)) : undefined,
					energy: typeof e.energy === 'number' ? Math.max(-20, Math.min(20, e.energy)) : undefined,
					resources: resources
				};
			}
			if (o?.requires && typeof o.requires === 'object') {
				opt.requires = {};
				for (const k of ['wood','stone','vine','water','torch','trap']) {
					if (o.requires[k] != null) opt.requires[k] = o.requires[k];
				}
			}
			safe.options.push(opt);
		}
		if (safe.options.length === 0) {
			safe.options.push({ label: '继续', risk: '低', next: null });
		}
		return safe;
	}
}

const aiService = new TextSurvivalAIService();
export default aiService; 